#include "StdAfx.h"
#include "DomainEndPoint.h"

using namespace Adaptive::Win32;
using namespace Adaptive::Network;
using namespace Adaptive::Network::Sockets;
using namespace Adaptive::Network::Dns;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
DomainEndPoint::DomainEndPoint() : IPEndPoint(IPAddress::Any, 0)
{
	_domainName = String::Empty;
	_dnsSuccess = false;
}
// Initializes a new instance of the class.
DomainEndPoint::DomainEndPoint(System::String ^domainNameOrAddress, short internetPort) : IPEndPoint(IPAddress::Any, internetPort)
{
	_domainName = domainNameOrAddress;
	_dnsSuccess = false;
	PerformDnsTask();
}
// Initializes a new instance of the class.
DomainEndPoint::DomainEndPoint(System::Net::IPAddress ^ipAddress, short internetPort) : 
	IPEndPoint(ipAddress, internetPort)
{
	_domainName = String::Empty;
	_dnsSuccess = false;
	PerformDnsTask();
}
// Initializes a new instance of the class.
DomainEndPoint::DomainEndPoint(System::Net::IPEndPoint ^remoteEndPoint) : IPEndPoint(remoteEndPoint->Address, remoteEndPoint->Port)
{
	_domainName = String::Empty;
	_dnsSuccess = false;
	PerformDnsTask();
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Properties
 *------------------------------------------------------------------------------*/
#pragma region Public Properties

String^ DomainEndPoint::DomainName::get()
{
	return _domainName;
}
void DomainEndPoint::DomainName::set(String^ value)
{
	_domainName = value;
	_dnsSuccess = false;
	PerformDnsTask();
}
array<String^>^ DomainEndPoint::DomainNameList::get()
{
	return _domainNameList;
}
bool DomainEndPoint::DnsSuccessful::get()
{
	return _dnsSuccess;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions

void DomainEndPoint::Clear()
{
	Address = IPAddress::Any;
	Port = 0;
	_domainName = String::Empty;
	_dnsSuccess = false;
	if (_domainNameList != nullptr)
	{
		Array::Clear(_domainNameList, 0, _domainNameList->Length);
		delete(_domainNameList);
	}
	_domainNameList=nullptr;

}
bool DomainEndPoint::TryDns()
{
	PerformDnsTask();
	return _dnsSuccess;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Private Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Private Methods / Functions

void DomainEndPoint::PerformDnsTask()
{
	array<ManagedDnsRecord^>^ resultList = nullptr;
	List<String^>^ nameList = nullptr;
	DnsQueryOption options;

	options = DnsQueryOption::AcceptTrunacted | DnsQueryOption::OnTheWireOnly | DnsQueryOption::Standard | DnsQueryOption::ReturnMessage ;

	if ((_domainName == nullptr) || (_domainName->Length == 0))
	{
		//Resolve by IP address (get the host name value).
		try
		{
			resultList = DnsQuery::PerformDnsQuery(Address->ToString(), DnsQueryType::CanonicalName, options);
			if (resultList == nullptr)
			{
				resultList = DnsQuery::PerformDnsQuery(Address->ToString(), DnsQueryType::DomainPointer, options);
				if (resultList == nullptr)
				{
					resultList = DnsQuery::PerformDnsQuery(Address->ToString(), DnsQueryType::DomainNameAliases, options);
					if (resultList == nullptr)
					{
						resultList = DnsQuery::PerformDnsQuery(Address->ToString(), DnsQueryType::All, options);
					}
				}
			}
		}
		catch(...)
		{
			resultList = nullptr;
		}
	}
	else
	{
		//Resolve by host name (get the IP Address value).
		try
		{
			resultList = DnsQuery::PerformDnsQuery(_domainName, DnsQueryType::Address, options);
		}
		catch(...)
		{
			resultList = nullptr;
		}
	}

	//Set values, if successful.
	_dnsSuccess = (resultList != nullptr);

	if (resultList != nullptr)
	{
		nameList = gcnew List<String^>();

		for each(ManagedDnsRecord^ item in resultList)
		{
			if (item->RecordType == DnsQueryType::Address)
			{
				Address = item->AddressRecord.IP;
			}
			else if ((item->RecordType == DnsQueryType::CanonicalName) || 
					(item->RecordType == DnsQueryType::DomainPointer))
			{
				nameList->Add( item->PointerRecord.HostName );
			}
		}
		delete(resultList);

		if ((_domainName->Length == 0) && (nameList->Count > 0))
			_domainName = nameList[0];

		if (_domainNameList != nullptr)
		{
			Array::Clear(_domainNameList, 0, _domainNameList->Length);
			delete(_domainNameList);
		}		
		_domainNameList = nameList->ToArray();
		delete(nameList);
	}

	resultList = nullptr;
}
#pragma endregion
